package id.co.rho.scoring.cid.changecontrol;

import java.lang.reflect.Method;
import java.util.List;

import id.co.rho.scoring.cid.changecontrol.entitychange.DeleteEntityChange;
import id.co.rho.scoring.cid.changecontrol.entitychange.UpdateEntityChange;
import id.co.rho.scoring.cid.changecontrol.entitychange.propertychange.PropertyChange;

import javax.persistence.EntityManager;

public class ChangeControlImpl implements ChangeControl{
	EntityManager entityManager;
	UpdateEntityChange updtEntityChange;
	DeleteEntityChange delEntityChange;
	Object classEntity;

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}

	public UpdateEntityChange getEntityChange() {
		return updtEntityChange;
	}

	public void setEntityInsert(Object classEntity){
		this.classEntity = classEntity;
	}

	public void setUpdateEntityChange(UpdateEntityChange entityChange) {
		this.updtEntityChange = entityChange;
	}
	public void setDeleteEntityChange(DeleteEntityChange entityChange) {
		this.delEntityChange = entityChange;
	}
	
	public void apply(Object entityDb, String fieldName, Object newValue) {
		try {
			Method setter = getSetterMethod(entityDb.getClass(), fieldName);
			if (entityDb != null)
				setter.invoke(entityDb, newValue);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	private static Method getSetterMethod(Class entityClazz, String fieldName) {
		fieldName = fieldName.substring(0, 1).toUpperCase()
				+ fieldName.substring(1); // uppercase first letter
		final String setterName = "set" + fieldName;
		Method m;
		for (int i = 0; i < entityClazz.getMethods().length; i++) {
			m = entityClazz.getMethods()[i];
			if (m.getName().equals(setterName) && m.getParameterTypes() != null
					&& m.getParameterTypes().length == 1) {
				return m;
			}
		}
		return null;
	}
	
	@Override
	public void executeInsertChange() {
		entityManager.persist(classEntity);
	}

	@Override
	public void executeUpdateChange() {
		try {
			Object persistentEntity = entityManager.find(
					Class.forName(updtEntityChange.getEntityType()),
					updtEntityChange.getEntityId());

			List<PropertyChange> propChanges = updtEntityChange.getPropertyChanges();
			if (propChanges.size() != 0) {
				for (int i = 0; i < propChanges.size(); i++) {
					apply(persistentEntity, propChanges.get(i)
							.getPropertyName(), propChanges.get(i)
							.getNewValue());
				}
			}
			entityManager.merge(persistentEntity);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	@Override
	public void executeDeleteChange() {
		try{
			Object persistanceEntity = entityManager.find(
					Class.forName(delEntityChange.getEntityType()),
					delEntityChange.getEntityId());
			entityManager.remove(persistanceEntity);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

}
